﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Text.RegularExpressions;
using System.Net;

namespace ftpWindows
{
    public partial class Form1 : Form
    {
        private bool localFolderTag = false; //本地文件夹是否打开
        private Socket cmdSocket;
        private Socket dataSocket;
        private string localFolderPath;
        private string remoteFolderPath="/";

        // 初始化socket
        private void initScoket()
        {
            int timeout = 500;
            cmdSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //命令端口套接字
            dataSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //数据端口套接字
            cmdSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, true);     //启用接收超时选项
            cmdSocket.ReceiveTimeout = timeout;//毫秒
            cmdSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, true);     //启用发送超时选项
            cmdSocket.SendTimeout = timeout;//毫秒
            dataSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, true);     //启用接收超时选项
            dataSocket.ReceiveTimeout = timeout;//毫秒
            dataSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, true);     //启用发送超时选项
            dataSocket.SendTimeout = timeout;//毫秒
        }
        public Form1()
        {
            InitializeComponent();
            initScoket();
        }
        
        //获取控制端口一行信息
        private string getCmdLn(out int status)
        {
            byte[] buffer = new byte[65536];
            int index = 0;
            byte[] read = new byte[1];
            do
            {
                int len = 0;
                try
                {
                    len = cmdSocket.Receive(read);
                }
                catch
                {
                    break;
                }
                if (len == 0) break;
                if (read[0] != '\r' && read[0] != '\n')
                {
                    buffer[index] = read[0];
                    index++;
                }
            } while (read[0] != '\n');

            byte[] ret = new byte[index];

            status = 0;
            bool flag = true;
            for (int i = 0; i < index; i++)
            {
                ret[i] = buffer[i];

                if (ret[i] < '0' || ret[i] > '9')
                {
                    flag = false;
                }
                else if (flag)
                {
                    status = status * 10 + ret[i] - '0';
                }
            }
            string res= Encoding.UTF8.GetString(ret,0,index);
            return res;
        }
        
        //获取数据端口一行信息
        private string getDataLn()
        {
            byte[] buffer = new byte[65536];
            int index = 0;
            byte[] read = new byte[1];
            do
            {
                int len = 0;
                try
                {
                    len = dataSocket.Receive(read);
                }
                catch
                {
                    break;
                }
                if (len == 0) break;
                if (read[0] != '\r' && read[0] != '\n')
                {
                    buffer[index] = read[0];
                    index++;
                }
            } while (read[0] != '\n');

            byte[] ret = new byte[index];
            for (int i = 0; i < index; i++)
            {
                ret[i] = buffer[i];
            }
            string res = Encoding.UTF8.GetString(ret, 0, index);
            return res;
        }
        
        //获取控制端口所有信息，一行一行获取，并显示在listbox3中
        private void getCmdInfo(out int status)
        {
            int oldStatus=0;
            status = 0;
            string s;
            while(true)
            {
                s = getCmdLn(out oldStatus);
                if (s == "") break;
                if (oldStatus != 0) status = oldStatus;
                listBox3.Items.Add(s);
                listBox3.SelectedIndex = listBox3.Items.Count - 1;
            }
        }
        
        //控制端口发送信息
        private void send(string s)
        {
            cmdSocket.Send(Encoding.UTF8.GetBytes(s));
            cmdSocket.Send(Encoding.UTF8.GetBytes("\r\n"));
        }
        
        // 打开被动模式 与数据端口建立连接
        private bool openDataConnect(IPAddress IP)
        {
            //打开被动模式获取数据端口
            int status;
            send("PASV");
            string s = getCmdLn(out status);
            if (status != 227)
            {
                return false;
            }
            string res;
            string[] retArray = Regex.Split(s, ",");
            if (retArray[5][2] != ')') res = retArray[5].Substring(0, 3);
            else res = retArray[5].Substring(0, 2);
            int dataPort = Convert.ToInt32(retArray[4]) * 256 + Convert.ToInt32(res);
            listBox3.Items.Add("Data Port is " + dataPort);
            listBox3.SelectedIndex = listBox3.Items.Count - 1;
            //建立数据端口连接
            IPEndPoint dataEP = new IPEndPoint(IP, dataPort);
            dataSocket.Connect(dataEP);
            return true;
        }

        //刷新/显示右侧服务器端文件列表
        private void showFtpFiles(string remoteFolderPath="/")
        {
            int status;
            // 显示服务器端文件列表
            send("LIST "+ remoteFolderPath);
            getCmdInfo(out status);
            string s = "";
            while (true)
            {
                s = getDataLn();
                if (s == "") break;
                string[] temp = Regex.Split(s, " ");
                listBox2.Items.Add(temp[temp.Length - 1]);
            }
            this.label8.Text = remoteFolderPath;
        }

        //登录 退出按钮
        private void connect_Click(object sender, EventArgs e)
        {
            if (connect.Text == "登录")
            {
                if (ip_input.Text == "")
                {
                    MessageBox.Show("请输入ip地址");
                    return;
                }
                if(port_input.Text=="")
                {
                    MessageBox.Show("请输入端口号");
                    return;
                }
                if (user.Text == "")
                {
                    MessageBox.Show("请输入用户名");
                    return;
                }
                if (pwd.Text == "")
                {
                    MessageBox.Show("请输入用户密码");
                    return;
                }
                Cursor cursor = Cursor.Current;
                Cursor.Current = Cursors.WaitCursor;
                try
                {
                    IPAddress IP = IPAddress.Parse(ip_input.Text);      //获取设置的IP地址
                    //IPAddress IP = IPAddress.Parse("192.168.0.104");      //获取设置的IP地址
                    int Port = Convert.ToInt32(port_input.Text);
                    //int Port = 21;       //获取设置的端口号
                    if(port_input.Text!="")
                    {
                        Port= int.Parse(port_input.Text);
                    }
                    IPEndPoint iPEndPoint = new IPEndPoint(IP, Port);    //指定的端口号和服务器的ip建立一个IPEndPoint对象
                    //建立控制端口连接
                    cmdSocket.Connect(iPEndPoint);
                    int status;
                    getCmdInfo(out status);
                    if (status != 220)
                    {
                        MessageBox.Show("error!\n建立连接失败，请检查ip地址和端口号");
                        return;
                    }
                    //登录

                    //用户名
                    string data = "USER " + user.Text;
                    //string data = "USER " + "sgsg";
                    send(data);
                    getCmdInfo(out status);
                    if (status != 331)
                    {
                        MessageBox.Show("error!\n登录失败，请检查用户名");
                        return;
                    }
                    //密码
                    data = "PASS " + pwd.Text;
                    //data = "PASS " + "123456";
                    send(data);
                    getCmdInfo(out status);
                    if(status!=230)
                    {
                        MessageBox.Show("error!\n登录失败，请检查密码");
                        return;
                    }
                    //开启被动模式
                    if(!openDataConnect(IP))
                    {
                        MessageBox.Show("error!\n被动模式打开失败");
                        return;
                    }
                    //显示服务器端列表
                    showFtpFiles("/");
                    label6.Text = ip_input.Text + ": ";
                    connect.Text = "退出";
                    upload.Enabled = true;
                    download.Enabled = true;
                }
                catch
                {
                    MessageBox.Show("error!\n登录失败");
                }
                finally
                {
                    Cursor.Current = cursor;
                }
            }
            else
            {
                Cursor cursor = Cursor.Current;
                Cursor.Current = Cursors.WaitCursor;
                //todo 断开命令端口连接
                send("QUIT");
                cmdSocket.Close();
                dataSocket.Close();
                initScoket();
                connect.Text = "登录";
                upload.Enabled = false;
                download.Enabled = false;
                listBox2.Items.Clear();
                listBox3.Items.Clear();
                Cursor.Current = cursor;
            }
        }

        //本地路径
        private void folder_TextChanged(object sender, EventArgs e)
        {
            string path = folder.Text;
            localFolderPath = path;
            string pattern = "*";
            try
            {
                List<FileInfo> folder = new DirectoryInfo(path).GetFiles(pattern).ToList();
                this.listBox1.Items.Clear();
                foreach (FileInfo file in folder)
                {
                    this.listBox1.Items.Add(file.Name);
                }
                localFolderTag = true;
            }
            catch
            {
                this.listBox1.Items.Clear();
                this.listBox1.Items.Add("文件夹打开失败");
                localFolderTag = false;
            }
            
        }

        //选择本地文件夹
        private void selectFolder_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog folder = new FolderBrowserDialog();
            folder.Description = "选择本地文件夹";  //提示的文字
            if (folder.ShowDialog() == DialogResult.OK)
            {
                this.folder.Text = folder.SelectedPath;
            }
        }
    }
}
